package com.iqiyi.pps.epg.core.service.auth.security;

import com.iqiyi.pps.epg.core.exception.ServiceException;
import com.iqiyi.pps.epg.core.model.auth.SysUser;
import com.iqiyi.pps.epg.core.service.auth.ResourceDetailService;
import com.iqiyi.pps.epg.core.utils.Constants;
import com.iqiyi.pps.epg.core.utils.SpringSecurityUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.stereotype.Service;

import java.util.*;

/*
 *
 * 最核心的地方，就是提供某个资源对应的权限定义，即getAttributes方法返回的结果。
 * 注意，我例子中使用的是AntUrlPathMatcher这个path matcher来检查URL是否与资源定义匹配，
 * 事实上你还要用正则的方式来匹配，或者自己实现一个matcher。
 *
 * 此类在初始化时，应该取到所有资源及其对应角色的定义
 *
 * 说明：对于方法的spring注入，只能在方法和成员变量里注入，
 * 如果一个类要进行实例化的时候，不能注入对象和操作对象，
 * 所以在构造函数里不能进行操作注入的数据。
 */
@Service
public class InvocationSecurityMetadataSourceService  implements
		FilterInvocationSecurityMetadataSource {

	private ResourceDetailService resourceDetailService;

	private UrlMatcher urlMatcher = new AntUrlPathMatcher();
	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public InvocationSecurityMetadataSourceService() {
	}

    public void init() {
        loadResourceDefine();
    }

/*	   private void loadResourceDefine() {
	        resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
	        Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
	        ConfigAttribute ca = new SecurityConfig("ROLE_ADMIN");
	        atts.add(ca);
	        resourceMap.put("/index.jsp", atts);
	        resourceMap.put("/i.jsp", atts);
	    }*/

	private void loadResourceDefine() {
        try {
            resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
            LinkedHashMap<String, String> requestMap = resourceDetailService.getRequestMap();

            for (Map.Entry<String, String> entry : requestMap.entrySet()) {

                String authorities = entry.getValue();
                Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
                for( String authority: authorities.split(",")) {
                    ConfigAttribute ca = new SecurityConfig(authority);
                    atts.add(ca);
                }

                resourceMap.put(entry.getKey(), atts);
            }
        } catch (Exception e) {
            throw new ServiceException("init security resource error",e);
        }
	}

	// According to a URL, Find out permission configuration of this URL.
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		// guess object is a URL.
        String url = ((FilterInvocation) object).getRequestUrl();
        Iterator<String> ite = resourceMap.keySet().iterator();

        UserDetails user = SpringSecurityUtils.getCurrentUser();
        long userId = -1;
        if(user instanceof SysUser) {
            userId = ((SysUser) user).getId();
        }

        if (userId != Constants.SUPER_ADMIN_ID) {
            while (ite.hasNext()) {
                String resURL = ite.next();
                if (url.matches(resURL)) {
//			if (urlMatcher.pathMatchesUrl(url, resURL)) {
                    return resourceMap.get(resURL);
                }
            }
        }

        return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

    public ResourceDetailService getResourceDetailService() {
        return resourceDetailService;
    }

    public void setResourceDetailService(ResourceDetailService resourceDetailService) {
        this.resourceDetailService = resourceDetailService;
    }
}
